package com.qingjiang.projectschedule.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qingjiang.projectschedule.mapper.ProjectInformationMapper;
import com.qingjiang.projectschedule.mapper.ProjectScheduleMapper;
import com.qingjiang.projectschedule.pojo.*;
import com.qingjiang.projectschedule.pojo.dto.ProjectNodeDelayReasonDTO;
import com.qingjiang.projectschedule.pojo.statistic.ProjectExecution;
import com.qingjiang.projectschedule.pojo.statistic.ProjectLag;
import com.qingjiang.projectschedule.pojo.statistic.ProjectLagList;
import com.qingjiang.projectschedule.service.*;
import com.qingjiang.projectschedule.utils.*;
import org.apache.poi.poifs.property.Child;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * @author jx
 * @description 针对表【project_information(项目信息表)】的数据库操作Service实现
 * @createDate 2024-03-15 09:53:46
 */
@Service
@Transactional
public class ProjectInformationServiceImpl extends ServiceImpl<ProjectInformationMapper, ProjectInformation>
        implements ProjectInformationService {
    @Autowired
    private ProjectInformationMapper projectInformationMapper;

    @Autowired
    private ProjectScheduleService scheduleService;

    @Autowired
    private ProjectNumService numService;

    @Autowired
    private DepartmentService departmentService;

    @Autowired
    private NodeDailyrecordService dailyrecordService;

    @Autowired
    private ConfigService configService;

    @Autowired
    private StatisticService statisticService;

    @Autowired
    private ProjectNodeService projectNodeService;

    @Autowired
    private StatisticChildService statisticChildService;


    //时间填入格式
    private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
    @Autowired
    private ProjectScheduleMapper projectScheduleMapper;
    @Autowired
    private ProjectScheduleServiceImpl projectScheduleServiceImpl;

    @Override
    public boolean addOne(ProjectAllInformation projectAllInformation) {
        ProjectInformation projectInformation = new ProjectInformation();
        projectInformation.setProjectId(projectAllInformation.getProjectId());
        projectInformation.setProjectName(projectAllInformation.getProjectName());
        projectInformation.setProjectContent(projectAllInformation.getProjectContent());
        projectInformation.setManager(projectAllInformation.getProjectManager().replaceAll(" ", ""));
        projectInformation.setAddTime(new Date());
        projectInformation.setDeptId(projectAllInformation.getDeptId());
        projectInformation.setProjectDepartment(departmentService.getDeptNameById(projectAllInformation.getDeptId()));
        projectInformation.setCurrentNodeid(1);
        int rows = projectInformationMapper.insert(projectInformation);
        return rows == 1;
    }

    @Override
    public boolean updateProject(ProjectAllInformation projectAllInformation) {
        LambdaUpdateWrapper<ProjectInformation> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(ProjectInformation::getProjectId, projectAllInformation.getProjectId())
                .set(ProjectInformation::getProjectName, projectAllInformation.getProjectName())
                .set(ProjectInformation::getProjectContent, projectAllInformation.getProjectContent())
                .set(ProjectInformation::getManager, projectAllInformation.getProjectManager())
                .set(ProjectInformation::getDeptId, projectAllInformation.getDeptId())
                .set(ProjectInformation::getProjectDepartment, departmentService.getDeptNameById(projectAllInformation.getDeptId()))
                .set(ProjectInformation::getAddTime, new Date());
        int rows = projectInformationMapper.update(null, updateWrapper);
        System.out.println("更新项目结果：" + rows);
        return rows == 1;
    }

    @Override
    public void getExcelTemplate(HttpServletResponse response) throws IOException {
        ByteArrayOutputStream baos = null;
        ServletOutputStream outputStream = null;
        try {
            /*String filePath = "static/项目导入模版.xlsx";
            Resource resource = new ClassPathResource(filePath);
            InputStream inputStream = new FileInputStream(resource.getFile());*/
            InputStream inputStream = new FileInputStream(new File("/usr/local/project/项目导入模版.xlsx"));
            byte[] buffer = new byte[1024];
            baos = new ByteArrayOutputStream();
            int len;
            while ((len = inputStream.read(buffer)) != -1) {
                baos.write(buffer, 0, len);
            }
            /*System.out.println("____--------------");
            System.out.println(Arrays.toString(baos.toByteArray()));*/
            response.setContentType("application/octet-stream");
            outputStream = response.getOutputStream();
            outputStream.write(baos.toByteArray());
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            baos.flush();
            baos.close();
            outputStream.flush();
            outputStream.close();
        }
    }

    @Override
    @Transactional
    public Result uploadExcel(MultipartFile file) {
        int num = 0;
        Workbook workbook = null;
        InputStream inputStream = null;
        StringBuilder err_1 = new StringBuilder();
        StringBuilder err_2 = new StringBuilder();
        try {
            inputStream = file.getInputStream();
            workbook = new XSSFWorkbook(inputStream);
            Sheet sheet = workbook.getSheetAt(0);
            for (int i = 2; i < CheckExcel.getRowCount(sheet); i++) {   // 遍历Sheet中的每一行，从第三行开始
                Row row = sheet.getRow(i);
                if (!checkProjectIsAdded(row.getCell(1).toString())) {
                    err_1.append(i - 1).append(" ");
                }
                int curNode = scheduleService.checkScheduleTime(row);
                if (curNode == -1) {
                    err_2.append(i - 1).append(" ");
                }
            }
            StringBuilder message = new StringBuilder();
            if (err_1.length() != 0) {
                message.append("第").append(err_1).append("个项目重复。");
            }
            if (err_2.length() != 0) {
                message.append("  ").append("第").append(err_2).append("个项目时间有误");
            }
            if (message.length() != 0) return Result.build(null, 801, message.toString(), false);
            for (int i = 2; i < CheckExcel.getRowCount(sheet); i++) {
                Row row = sheet.getRow(i);
                if (row != null) {
                    int curNode = scheduleService.checkScheduleTime(row);
                    String projectId = numService.generateProjectId();
                    ProjectInformation projectInformation = new ProjectInformation();
                    projectInformation.setProjectId(projectId);
                    projectInformation.setProjectName(row.getCell(1).toString());
                    projectInformation.setProjectDepartment(row.getCell(2).toString());
                    projectInformation.setDeptId(departmentService.getDeptIdByName(row.getCell(2).toString()));
                    projectInformation.setManager(row.getCell(3).toString().replaceAll(" ", ""));
                    projectInformation.setProjectContent(row.getCell(4).toString());
                    projectInformation.setCurrentNodeid(curNode);
                    projectInformation.setAddTime(new Date());
                    projectInformationMapper.insert(projectInformation);
                    scheduleService.uploadExcel(row, projectId, curNode);
                }
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return Result.ok(null);
    }

    @Override
    public Boolean checkProjectIsAdded(String projectName) {
        LambdaQueryWrapper<ProjectInformation> queryWrapper = new LambdaQueryWrapper<>();
        int curYear = Calendar.getInstance().get(Calendar.YEAR);
        String beginYear = curYear + "-01-01";
        String endYear = (curYear + 1) + "-01-01";
        queryWrapper.eq(ProjectInformation::getProjectName, projectName).between(ProjectInformation::getAddTime, beginYear, endYear);
        Integer count = projectInformationMapper.selectCount(queryWrapper);
        if (count > 0) return false;
        return true;
    }

    //ADD
    @Override
    public List<ShowProjectAllInformation> query_unfinished() {
        LambdaQueryWrapper<ProjectInformation> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ProjectInformation::getIsFinished, 0);
        List<ProjectInformation> project_unfinished = projectInformationMapper.selectList(queryWrapper);
        System.out.println("查询未完成的项目");

        List<ShowProjectAllInformation> result = new ArrayList<>();
        for (ProjectInformation project : project_unfinished) {
            System.out.println("查询项目:" + project.getProjectId());
            ShowProjectAllInformation projectInfo = new ShowProjectAllInformation();
            projectInfo.setProjectInformation(project);
            projectInfo.setDelay_reason("延期原因");
            projectInfo.setIs_check(project.getIsCheck() == 0 ? "免考核" : "考核");
            projectInfo.setIs_cancel(project.getIsCancel() == 1 ? "取消" : "进行");

            System.out.println("查询项目的所有节点信息" + project.getProjectId());
            List<ProjectSchedule> project_node_info = scheduleService.queryProject(project.getProjectId());
//            projectInfo.setNode(project_node_info);


            Date curNode = project_node_info.get(project.getCurrentNodeid() - 1).getScheduleEndTime();
            Date today = new Date();

            long milliseconds1 = today.getTime();
            long milliseconds2 = curNode.getTime();
            System.out.println("节点计划时间：" + curNode + " " + milliseconds2);
            System.out.println("当前时间：" + today + " " + milliseconds1);
            int daysBetween = (int) ((milliseconds2 - milliseconds1) / (24 * 60 * 60 * 1000));
            if (daysBetween <= 0) {
                projectInfo.setCur_node_state(3);
            } else if (daysBetween <= 5) {
                projectInfo.setCur_node_state(2);
            } else {
                projectInfo.setCur_node_state(1);
            }
            //
            System.out.println("daysBetween:" + daysBetween);
            result.add(projectInfo);
        }
        return result;
    }

    @Override
    public Map<String, List<ProjectInformation>> getDelayProjectList() {
        LambdaQueryWrapper<ProjectInformation> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ProjectInformation::getIsFinished, 0)
                .eq(ProjectInformation::getIsCancel, 0);
        queryWrapper.orderByAsc(ProjectInformation::getDeptId);

        List<ProjectInformation> project_unfinished = projectInformationMapper.selectList(queryWrapper);
        List<ProjectInformation> postponedProjects = new ArrayList<>();
        List<ProjectInformation> checkProjects = new ArrayList<>();
        for (ProjectInformation project : project_unfinished) {
            int curNodeId = project.getCurrentNodeid();
            ProjectSchedule curNode = scheduleService.getCurNode(project.getProjectId(), curNodeId);

            //判断当前节点状态
            Date curNodeTime = curNode.getDelayTotime();
            if (curNodeTime == null) {
                continue;
            }
            int WARNING = configService.getYellowDays();
            long dayDiff = DateUtil.calDayDiff(curNodeTime);

            //提前多少天发送短信
            int aheadOfDay = configService.getMessageDays();

            if (dayDiff == -aheadOfDay) {
                postponedProjects.add(project);
            } else if (dayDiff == WARNING - aheadOfDay) {
                checkProjects.add(project);
            }
        }
        Map<String, List<ProjectInformation>> result = new HashMap<>();
        result.put("postponedProjects", postponedProjects);
        result.put("checkProjects", checkProjects);
        return result;
    }

    @Override
    public Map<String, Object> queryByCond(ProjectQueryCond cond) {
//        Page<ProjectInformation> projectInformationPage = new Page<>(cond.getPage(), cond.getPageSize());
        LambdaQueryWrapper<ProjectInformation> queryWrapper = new LambdaQueryWrapper<>();
//        queryWrapper.eq(ProjectInformation::getIsLock, 0);
//        1.筛选考核年份
        if (cond.getYear() != null && cond.getYear().length() != 0) {
            queryWrapper.like(ProjectInformation::getAddTime, cond.getYear());
        } else {
            Calendar instance = Calendar.getInstance();
            int curYear = instance.get(Calendar.YEAR);
            System.out.println("year:" + curYear);
            queryWrapper.like(ProjectInformation::getAddTime, curYear);
        }

//        2.筛选项目是否完成 未完成为1（默认0未完成）
        if (cond.getProgress() == 1 || cond.getProgress() == 0) {
            queryWrapper.eq(ProjectInformation::getIsCancel, 0).
                    eq(ProjectInformation::getIsFinished, 0);
        } else if (cond.getProgress() == 2) {
            queryWrapper.eq(ProjectInformation::getIsCancel, 0).
                    eq(ProjectInformation::getIsFinished, 1);
        } else if (cond.getProgress() == 3) {
            queryWrapper.eq(ProjectInformation::getIsCancel, 1);
        }

        queryWrapper.orderByAsc(ProjectInformation::getDeptId);
        //3.指定了查询单位，未指定则查询全部部门
        List<Integer> queryDept = cond.getDepartments();
        if (queryDept != null && queryDept.size() != 0 && queryDept.get(0) != null) {
            queryWrapper.in(ProjectInformation::getDeptId, cond.getDepartments());
        }

        // 4. 新增对name属性的模糊查询
        if (cond.getName() != null && !cond.getName().isEmpty()) {
            queryWrapper.like(ProjectInformation::getProjectName, cond.getName());
        }

        List<ProjectInformation> project_unfinished = new ArrayList<>();

        project_unfinished = projectInformationMapper.selectList(queryWrapper);

        int WARNING = configService.getYellowDays();
        List<ShowProjectAllInformation> result = new ArrayList<>();
        //0:取消  1：进行    2：提醒（黄牌）    3：滞后（红牌）
        int[] statusCnt = new int[4];
        //对每一个项目查询其每一个节点
        for (ProjectInformation project : project_unfinished) {
            //记录当前项目所有信息
            ShowProjectAllInformation projectInfo = new ShowProjectAllInformation();
            projectInfo.setProjectInformation(project);
            List<ProjectSchedule> project_node_info = scheduleService.queryProject(project.getProjectId());

            //判断当前节点状态
            Date curNodeTime = project_node_info.get(project.getCurrentNodeid() - 1).getDelayTotime();
            Date curNode_actualStartTime = project_node_info.get(project.getCurrentNodeid() - 1).getActualStartTime();
            int curNodeId = project.getCurrentNodeid();

            int yellowCard = 0, redCard = 0;
            //统计当前节点之前红黄牌数量
            for (int i = 0; i < curNodeId - 1; i++) {
                int state = project_node_info.get(i).getNodeState();
                if (state == 2) {
                    yellowCard++;
                } else if (state == 3) {
                    redCard++;
                }
            }

            int nodeState = 1;
            if (curNode_actualStartTime != null) {
                nodeState = project_node_info.get(project.getCurrentNodeid() - 1).getNodeState();
            } else {
                if (curNodeTime != null) {
                    long dayDiff = DateUtil.calDayDiff(curNodeTime);
                    //没有指定日期，则判断节点状态
                    //fixme:取消项目状态为0
                    if (project.getIsCancel() != 1) {
                        if (dayDiff > 0) {
                            if (dayDiff <= WARNING) {
                                nodeState = 2;
                                yellowCard++;
                            } else {
                                nodeState = 3;
                                redCard++;
                            }
                        }
                    }
                }
            }

            //调整当前节点状态
            project_node_info.get(curNodeId - 1).setNodeState(nodeState);
            scheduleService.setNodeState(project.getProjectId(), project.getCurrentNodeid(), nodeState);
            projectInfo.setCur_node_state(nodeState);
            projectInfo.setNode(Convert_ProjectScheduleVO.convertProjectScheduleVOList(project_node_info));
            projectInfo.setNodePO(project_node_info);
//            projectInfo.setNode(project_node_info);

            //更新红黄牌数量
            setCardNum(project.getProjectId(), yellowCard, redCard);

            //设置滞后原因为当前节点滞后原因
//            if (nodeState == 3) {
//                String delay_reason = project_node_info.get(project.getCurrentNodeid() - 1).getDelayReason();
//                projectInfo.setDelay_reason(delay_reason == null ? "未写滞后原因" : delay_reason);
//            }
            //是否按当前节点状态查询，只统计未取消项目
            if (project.getIsCancel() != 1) {
                //查询红黄牌
                if (cond.getState() == 2 || cond.getState() == 3) {
                    boolean found = false;
                    for (int i = 0; i < curNodeId; i++) {
                        if (project_node_info.get(i).getNodeState() == cond.getState()) {
                            found = true;
                            break;
                        }
                    }
                    if (found) {
                        result.add(projectInfo);
                        for (int i = 0; i < curNodeId; i++) {
                            int state = project_node_info.get(i).getNodeState();
                            statusCnt[state]++;
                        }
                    }
                } else if (cond.getState() == 4 || cond.getState() == 5) {
                    if (nodeState + 2 == cond.getState()) {
                        result.add(projectInfo);
                        for (int i = 0; i < curNodeId; i++) {
                            int state = project_node_info.get(i).getNodeState();
                            statusCnt[state]++;
                        }
                    }
                } else if (cond.getState() == 0) {
                    result.add(projectInfo);
                    for (int i = 0; i < curNodeId; i++) {
                        int state = project_node_info.get(i).getNodeState();
                        statusCnt[state]++;
                    }
                }
            } else {
                result.add(projectInfo);
                statusCnt[0]++;
            }
        }
        Map<String, Object> res = new HashMap<>();
        statusCnt[1] = result.size();
        int fromIndex = (cond.getPage() - 1) * cond.getPageSize();
        // todo
        res.put("result", result.subList(fromIndex, Math.min(fromIndex + cond.getPageSize(), result.size())));
        res.put("statusCnt", statusCnt);
        res.put("total", result.size());
//        res.put("all", result);
        return res;
    }

    @Override
    public boolean setCurrentNodeid(String projectId, int curNode) {
        System.out.println("设置下一个节点");
        LambdaUpdateWrapper<ProjectInformation> updateWrapper = new LambdaUpdateWrapper<>();
        //fixme: 找到下一个不为空的节点
        int nextNodeId = curNode + 1;
        //判断当前节点是否为空
        while (nextNodeId <= 7) {
            ProjectSchedule projectSchedule = scheduleService.getCurNode(projectId, nextNodeId);
            if (projectSchedule.getScheduleStartTime() != null && !projectSchedule.getScheduleStartTime().equals("")) {
                break;
            }
            nextNodeId++;
        }
        if (nextNodeId > 7) {
            nextNodeId = 7;
        }
        System.out.println("下一个节点为" + nextNodeId);
        //fixme:7号节点不标记完成，待考核计入数据后再标记完成
        updateWrapper.eq(ProjectInformation::getProjectId, projectId).set(ProjectInformation::getCurrentNodeid, nextNodeId);
        Integer rows = projectInformationMapper.update(null, updateWrapper);
        return rows == 1;
    }

    @Override
    public boolean setIscheck(String project_id, int is_check) {
        LambdaUpdateWrapper<ProjectInformation> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(ProjectInformation::getProjectId, project_id).set(ProjectInformation::getIsCheck, is_check);
        Integer rows = projectInformationMapper.update(null, updateWrapper);
        return rows == 1;
    }

    @Override
    public boolean setIscancel(String project_id, int is_cancel) {
        LambdaUpdateWrapper<ProjectInformation> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(ProjectInformation::getProjectId, project_id).set(ProjectInformation::getIsCancel, is_cancel);
        Integer rows = projectInformationMapper.update(null, updateWrapper);
        return rows == 1;
    }

    @Override
    public int queryProjectNum(int deptId) {
        LambdaQueryWrapper<ProjectInformation> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ProjectInformation::getDeptId, deptId);
        return projectInformationMapper.selectCount(queryWrapper);
    }

    @Override
    public int queryProjectNonlock(int deptId) {
        LambdaQueryWrapper<ProjectInformation> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ProjectInformation::getIsLock, 0)
                .eq(ProjectInformation::getDeptId, deptId);
        return projectInformationMapper.selectCount(queryWrapper);
    }

    @Override
    public int queryProjectFinish(int deptId) {
        LambdaQueryWrapper<ProjectInformation> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ProjectInformation::getIsFinished, 1).eq(ProjectInformation::getDeptId, deptId);
        return projectInformationMapper.selectCount(queryWrapper);
    }

    @Override
    public int queryProjectCancel(int deptId) {
        LambdaQueryWrapper<ProjectInformation> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ProjectInformation::getIsLock, 0)
                .eq(ProjectInformation::getIsCancel, 1).eq(ProjectInformation::getDeptId, deptId);
        return projectInformationMapper.selectCount(queryWrapper);
    }

    /**
     * 统计部门未完成项目，未完成（未锁定）
     *
     * @param deptId
     * @return
     */
    @Override
    public List<ProjectInformation> queryProjectUnfinish(int deptId) {
        LambdaQueryWrapper<ProjectInformation> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ProjectInformation::getIsFinished, 0)
                .eq(ProjectInformation::getIsLock, 0)
                .eq(ProjectInformation::getDeptId, deptId);
        List<ProjectInformation> result = projectInformationMapper.selectList(queryWrapper);
        return result;
    }

    @Override
    public ProjectInformation queryByProjectID(String projectID) {
        LambdaQueryWrapper<ProjectInformation> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ProjectInformation::getProjectId, projectID);
        return projectInformationMapper.selectOne(queryWrapper);
    }

    @Override
    public Result getLockedProject(Integer page, Integer pageSize) {
        Page<ProjectInformation> projectInformationPage = new Page<>(page, pageSize);
        LambdaQueryWrapper<ProjectInformation> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ProjectInformation::getIsLock, 1);
        Page pageResult = projectInformationMapper.selectPage(projectInformationPage, queryWrapper);
        List<ProjectInformation> lockedProject = pageResult.getRecords();
        Map<String, Object> map = new HashMap<>();
        map.put("total", pageResult.getTotal());
        map.put("list", lockedProject);
        return Result.ok(map);
    }

    @Override
    public Result unLockProject(String projectId) {
        LambdaUpdateWrapper<ProjectInformation> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(ProjectInformation::getProjectId, projectId).set(ProjectInformation::getIsLock, 0);
        projectInformationMapper.update(null, updateWrapper);
        return Result.ok(null);
    }

    @Override
    public Result getProjectStatisticByYearAndMonth(Integer year, Integer month, boolean isSchedule) {
        if (month == -1) return getProjectStatisticByYear(year);
        Calendar instance = Calendar.getInstance();
        int curYear = instance.get(Calendar.YEAR);
        int curMonth = instance.get(Calendar.MONTH) + 1;
        int curDay = instance.get(Calendar.DAY_OF_MONTH);
        String curYearMonth = String.valueOf(year) + String.valueOf(month);
        //历史时间 已经 本月26号（含26号）及以后均查询历史数据
        if (year < curYear || (year == curYear && month < curMonth) || (year == curYear && month == curMonth && curDay > 25)) {
            return statisticService.getHistoryProjectStatisticByYearAndMonth(curYearMonth);
        }
        // 只有当月 1-25号（含25号）查询实时数据 并记录更新数据库
        String beginYear = year + "-01-01";
        String endYear = (year + 1) + "-01-01";
        //获取所有单位
        List<Department> deptList = departmentService.getDeptList();
        //定义结果集
        List<Map<String, Object>> list = new ArrayList<>();
        //遍历所有单位，各个单位分别处理
        for (Department department : deptList) {
            Map<String, Object> eachDeptMap = new HashMap<>();
            LambdaQueryWrapper<ProjectInformation> queryWrapper = new LambdaQueryWrapper<>();
            //查询所属同一个单位中的所有未结束项目且未取消项目id、当前节点、项目名称
            queryWrapper.select(ProjectInformation::getProjectId, ProjectInformation::getCurrentNodeid, ProjectInformation::getProjectName)
                    .eq(ProjectInformation::getDeptId, department.getDeptId())
                    .eq(ProjectInformation::getIsFinished, 0)
                    .eq(ProjectInformation::getIsCancel, 0)
                    .between(ProjectInformation::getAddTime, beginYear, endYear);
            List<Map<String, Object>> projects = projectInformationMapper.selectMaps(queryWrapper);
            Integer yellow_sum = 0;
            Integer red_sum = 0;
            int delayProjectSum = 0;
            //对每个项目分别处理
            for (Map<String, Object> project : projects) {
                String projectId = (String) project.get("project_id");
                String projectName = (String) project.get("project_name");
                int curNodeId = (Integer) project.get("current_nodeid");
                int curNodeState = 0;
                int lastNode = 1;
                int lastNodeState = 0;
                //如果当前月不是1月 ，则查询该项目上个月考核的最后一个节点的是哪个，及其上个月最后统计时所处的状态
                if (month != 1) {
                    List<Map<String, Object>> lastNodeAndState = statisticService.getLastNodeAndState(projectId,
                            String.valueOf(curYear) + (month - 1));
                    if (lastNodeAndState != null && !lastNodeAndState.isEmpty()) {
                        lastNode = (Integer) lastNodeAndState.get(0).get("last_node");
                        lastNodeState = (Integer) lastNodeAndState.get(0).get("last_node_state");
                    }
                }
                //获取上个月统计的最后一个节点(包含该节点)到当前该项目所处节点 中间所有节点及其状态
                List<Map<String, Object>> nodesByCond = scheduleService.getNodesByCond(projectId, lastNode, curNodeId);
                StringBuilder yellowNodes = new StringBuilder();
                StringBuilder redNodes = new StringBuilder();
                //标记该项目本月是否含红黄牌，若没有则不计入数据库
                boolean flag = false;
                //遍历 上述查询的所有节点
                for (Map<String, Object> node : nodesByCond) {
                    int nodeId = (Integer) node.get("node_id");
                    int nodeState = (Integer) node.get("node_state");
                    //如果上个月统计的最后一个节点当时的状态跟本月所处状态不一样做特殊处理
                    //统计 上述查询所有节点 黄牌、红牌数量
                    if ((nodeId == lastNode && nodeState != lastNodeState) || nodeId != lastNode) {
                        if (nodeState == 2) {
                            yellowNodes.append(nodeId).append(",");
                            yellow_sum++;
                            flag = true;
                        } else if (nodeState == 3) {
                            redNodes.append(nodeId).append(",");
                            red_sum++;
                            flag = true;
                        }
                    }
                    if (nodeId == curNodeId) curNodeState = nodeState;
                }
                if (flag) {
                    delayProjectSum++;
                    statisticService.putCurMonthStatistic(projectId, projectName, department.getDeptId(), curYearMonth, curNodeId,
                            curNodeState, yellowNodes.toString(), redNodes.toString());
                }
                /*//若出于当月的1-25号则实施更新数据库
                if (curDay <= 25) {
                    //在当月25号 将本月完成的项目标记为已完成
                    if (curDay == 25 && curNodeId == 7) {
                        Date nodeActualEndTime = scheduleService.getNodeActualEndTime(projectId, curNodeId);
                        if (nodeActualEndTime != null) {
                            projectInformationMapper.update(null, new LambdaUpdateWrapper<ProjectInformation>().set
                            (ProjectInformation::getIsFinished, 1)
                                    .eq(ProjectInformation::getProjectId, projectId));
                        }
                    }
                    if (flag)
                        statisticService.putCurMonthStatistic(projectId, projectName, department.getDeptId(), curYearMonth, curNodeId,
                        curNodeState, yellowNodes.toString(), redNodes.toString());
                }*/
            }
            //根据全重计算得分
            Double yellow_point = yellow_sum * department.getYellowWeight();
            Double red_point = red_sum * department.getRedWeight();
            eachDeptMap.put("deptId", department.getDeptId());
            eachDeptMap.put("deptName", department.getDeptName());
            eachDeptMap.put("projectSum", projects.size());
            eachDeptMap.put("delayProjectSum", delayProjectSum);
            eachDeptMap.put("yellowSum", yellow_sum);
            eachDeptMap.put("redSum", red_sum);
            Double point = DoubleUtil.round(yellow_point + red_point, 2);
            eachDeptMap.put("dPoints", point);
            list.add(eachDeptMap);
            //保存当月项目总数、以及分数
            statisticChildService.insertOrUpdate(department.getDeptId(), curYearMonth, projects.size(), point);
        }
        return Result.ok(list);
    }

    @Override
    public Result getProjectStatisticByYear(Integer year) {
        String beginYear = year + "-01-01";
        String endYear = (year + 1) + "-01-01";
        List<Department> deptList = departmentService.getDeptList();
        List<Map<String, Object>> list = new ArrayList<>();
        for (Department department : deptList) {
            Map<String, Object> eachDeptMap = new HashMap<>();
            LambdaQueryWrapper<ProjectInformation> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.select(ProjectInformation::getYellowCard, ProjectInformation::getRedCard)
                    .eq(ProjectInformation::getDeptId, department.getDeptId())
                    .eq(ProjectInformation::getIsCancel, 0)
                    .between(ProjectInformation::getAddTime, beginYear, endYear);
            List<Map<String, Object>> maps = projectInformationMapper.selectMaps(queryWrapper);
            Integer yellow_sum = 0;
            Integer red_sum = 0;
            Integer delayProjectSum = 0;
            for (Map<String, Object> map : maps) {
                boolean flag = false;
                for (Map.Entry<String, Object> entry : map.entrySet()) {
                    if ("yellow_card".equals(entry.getKey())) yellow_sum += (Integer) entry.getValue();
                    else red_sum += (Integer) entry.getValue();
                    if ((Integer) entry.getValue() != 0) flag = true;
                }
                if (flag) delayProjectSum++;
            }
            Double yellow_point = yellow_sum * department.getYellowWeight();
            Double red_point = red_sum * department.getRedWeight();
            eachDeptMap.put("deptId", department.getDeptId());
            eachDeptMap.put("deptName", department.getDeptName());
            eachDeptMap.put("projectSum", maps.size());
            eachDeptMap.put("delayProjectSum", delayProjectSum);
            eachDeptMap.put("yellowSum", yellow_sum);
            eachDeptMap.put("redSum", red_sum);
            eachDeptMap.put("dPoints", DoubleUtil.round(yellow_point + red_point, 2));
            list.add(eachDeptMap);
        }
        return Result.ok(list);
    }

    @Override
    public List<Map<String, Object>> getAllProjectByColor(Integer deptId, Integer year, Integer month, String color) {
        if (month == -1) return getAllProjectOneYearByColor(deptId, year, color);
        String curYearMonth = String.valueOf(year) + String.valueOf(month);
        List<Map<String, Object>> allProjectByDateColorDeptId = statisticService.getAllProjectByDateColorDeptId(deptId, curYearMonth,
                color);
        return allProjectByDateColorDeptId;
    }

    @Override
    public List<Map<String, Object>> getAllProjectOneYearByColor(Integer deptId, Integer year, String color) {
        String beginYear = year + "-01-01";
        String endYear = (year + 1) + "-01-01";
        LambdaQueryWrapper<ProjectInformation> queryWrapper = new LambdaQueryWrapper<>();
        if ("yellow".equals(color)) {
            queryWrapper.select(ProjectInformation::getProjectId, ProjectInformation::getProjectName, ProjectInformation::getYellowCard).ne(ProjectInformation::getYellowCard, 0);
        } else {
            queryWrapper.select(ProjectInformation::getProjectId, ProjectInformation::getProjectName, ProjectInformation::getRedCard).ne(ProjectInformation::getRedCard, 0);
        }
        queryWrapper.eq(ProjectInformation::getDeptId, deptId).eq(ProjectInformation::getIsCancel, 0).between(ProjectInformation::getAddTime, beginYear, endYear);
        List<Map<String, Object>> maps = projectInformationMapper.selectMaps(queryWrapper);
        for (Map<String, Object> map : maps) {
            if ("yellow".equals(color)) map.put("node_name", "共" + map.get("yellow_card") + "个");
            else map.put("node_name", "共" + map.get("red_card") + "个");
            String projectId = (String) map.get("project_id");
            List<Map<String, Object>> nodes = scheduleService.getNodeByColor(projectId, (String) map.get("project_name"), color);
            map.put("children", nodes);
        }
        return maps;
    }

    @Override
    public boolean setCardNum(String projectID, int yellow, int red) {
        LambdaUpdateWrapper<ProjectInformation> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(ProjectInformation::getProjectId, projectID)
                .set(ProjectInformation::getYellowCard, yellow)
                .set(ProjectInformation::getRedCard, red);
        Integer rows = projectInformationMapper.update(null, updateWrapper);
        return rows == 1;
    }

    @Override
    public List<ProjectExecution> queryProjectExecution() {
        //1. 获取所有责任单位
        List<Department> departments = departmentService.getDeptList();
        List<ProjectExecution> result = new ArrayList<>();
        //2. 查询每个单位的项目实施情况
        for (Department dept : departments) {
            int deptId = dept.getDeptId();
            ProjectExecution projectExecution = new ProjectExecution();
            List<Integer> nodeFinishCnt = new ArrayList<Integer>(8);
            int finish = queryProjectFinish(deptId);
            for (int i = 0; i < 8; i++) {
//                nodeFinishCnt.add(finish);
                nodeFinishCnt.add(0);
            }
            //3. 查询单位未完成的项目
            List<ProjectInformation> projectUnfinish = queryProjectUnfinish(deptId);
            //4. 未完成项目当前节点之前的节点已经完成
            for (ProjectInformation project : projectUnfinish) {
                int curNodeId = project.getCurrentNodeid();
                nodeFinishCnt.set(curNodeId - 1, nodeFinishCnt.get(curNodeId - 1) + 1);
//                for (int i = 0; i < project.getCurrentNodeid() - 1; i++) {
//                    nodeFinishCnt.set(i, nodeFinishCnt.get(i) + 1);
//                }
            }

            //5. 项目实施情况统计表
            int total = queryProjectNum(deptId);
            int start = queryProjectNonlock(deptId);
            int cancel = queryProjectCancel(deptId);
            Map<String, Integer> statusCnt = new HashMap<>();
            statusCnt.put("start", start);
            statusCnt.put("finish", finish);
            statusCnt.put("nonStart", total - start);
            statusCnt.put("cancel", cancel);

            projectExecution.setDepartment(dept.getDeptName());
            projectExecution.setProjectNum(total);
            projectExecution.setNodeFinishCnt(nodeFinishCnt);
            projectExecution.setStatusCnt(statusCnt);
            result.add(projectExecution);
        }
        return result;
    }

    @Override
    public List<ProjectLag> queryProjectLag() {
        //1. 获取所有责任单位
        List<Department> departments = departmentService.getDeptList();
        List<ProjectLag> result = new ArrayList<>();
        //2. 查询每个单位的项目实施情况
        for (Department dept : departments) {
            int deptId = dept.getDeptId();
            ProjectLag projectLag = new ProjectLag();
            List<Integer> nodeDelayCnt = new ArrayList<Integer>(7);
            int finish = queryProjectFinish(deptId);
            for (int i = 0; i < 7; i++) {
                nodeDelayCnt.add(0);
            }
            //3. 查询单位未完成的项目
            List<ProjectInformation> projectUnfinish = queryProjectUnfinish(deptId);
            int totalDelay = 0;
            //4. 未完成项目当前节点之前的节点已经完成
            for (ProjectInformation project : projectUnfinish) {
                int curNodeId = project.getCurrentNodeid();
                Date scheduleEndTime = scheduleService.getNodeEndTime(project.getProjectId(), curNodeId).getDelayTotime();
                long diff = DateUtil.calDayDiff(scheduleEndTime);
                if (diff <= 0) {
                    nodeDelayCnt.set(curNodeId - 1, nodeDelayCnt.get(curNodeId - 1) + 1);
                    totalDelay++;
                }
            }
            //5. 项目滞后情况统计表
            int total = queryProjectNum(deptId);
            projectLag.setDepartment(dept.getDeptName());
            projectLag.setProjectNum(total);
            projectLag.setNodeDelayCnt(nodeDelayCnt);
            projectLag.setTotalDelay(totalDelay);
            result.add(projectLag);
        }

        return result;
    }

    @Override
    public List<ProjectLagList> queryProjectLagList() {
        //1. 获取所有责任单位
        List<Department> departments = departmentService.getDeptList();
        List<ProjectLagList> result = new ArrayList<>();
        //2. 查询每个单位的项目实施情况
        for (Department dept : departments) {
            int deptId = dept.getDeptId();
            //3. 查询单位未完成的项目
            List<ProjectInformation> projectUnfinish = queryProjectUnfinish(deptId);
            //4. 未完成项目当前节点之前的节点已经完成
            for (ProjectInformation project : projectUnfinish) {
                int curNodeId = project.getCurrentNodeid();
                ProjectSchedule projectSchedule = scheduleService.getNodeEndTime(project.getProjectId(), curNodeId);
                Date scheduleEndTime = projectSchedule.getDelayTotime();
                long diff = DateUtil.calDayDiff(scheduleEndTime);
                if (diff <= 0) {
                    ProjectLagList projectLagList = new ProjectLagList();
                    projectLagList.setDepartment(dept.getDeptName());
                    projectLagList.setProjectName(project.getProjectName());
                    String nodeName = projectNodeService.getNodeNameById(curNodeId);
                    projectLagList.setDelayNode(curNodeId + ". " + nodeName);
                    projectLagList.setPlanEndTime(scheduleEndTime);
                    projectLagList.setDelayReason(projectSchedule.getDelayReason());
                    result.add(projectLagList);
                }
            }
        }
        return result;
    }

    public boolean setCancelReason(NodeOperation operation) {
        LambdaUpdateWrapper<ProjectInformation> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(ProjectInformation::getProjectId, operation.getProjectId())
                .set(ProjectInformation::getCancelReason, operation.getCancelReason())
                .set(ProjectInformation::getIsCancel, 1);
        Integer rows = projectInformationMapper.update(null, updateWrapper);
        statisticService.deleteCurrentMonthCancelProject(operation.getProjectId());
        return rows == 1;
    }

    @Override
    public void updateProjectForFinish() {
        LambdaQueryWrapper<ProjectInformation> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.select(ProjectInformation::getProjectId, ProjectInformation::getCurrentNodeid)
                .eq(ProjectInformation::getIsFinished, 0)
                .eq(ProjectInformation::getIsCancel, 0);
        List<Map<String, Object>> maps = projectInformationMapper.selectMaps(queryWrapper);
        for (Map<String, Object> map : maps) {
            if ((Integer) map.get("current_nodeid") == 7) {
                Date nodeActualEndTime = scheduleService.getNodeActualEndTime((String) map.get("project_id"), 7);
                if (nodeActualEndTime != null) {
                    projectInformationMapper.update(null,
                            new LambdaUpdateWrapper<ProjectInformation>().set(ProjectInformation::getIsFinished, 1)
                                    .eq(ProjectInformation::getProjectId, (String) map.get("project_id")));
                }
            }
        }
    }

    @Override
    public void exportProjectByColor(Integer year, Integer month, String color,Integer roleId,Integer deptId, HttpServletResponse response) throws IOException {
        Workbook workbook = ExcelTemplateGenerator.ExcelHeader(color);
        Sheet sheet = workbook.getSheetAt(0);
        int rowIndex = 1;
        List<Department> deptList = departmentService.getDeptList();
        // 对应项目情况统计的权限，123看查看所有部门，45只能查看自己部门
        if (roleId==4 || roleId==5){
            deptList = deptList.stream().filter(department -> department.getDeptId().equals(deptId)).collect(Collectors.toList());
        }
        for (Department department : deptList) {
            String deptName = department.getDeptName();
            List<Map<String, Object>> allProjectByColor = getAllProjectByColor(department.getDeptId(), year, month, color);
            for (Map<String, Object> eachProject : allProjectByColor) {
                String projectName = (String) eachProject.get("project_name");
                List<Map<String, Object>> children = (List<Map<String, Object>>) eachProject.get("children");
                for (Map<String, Object> child : children) {
                    Row row = sheet.createRow(rowIndex);
                    row.createCell(0).setCellValue(rowIndex++);
                    row.createCell(1).setCellValue(deptName);
                    row.createCell(2).setCellValue(projectName);
                    row.createCell(3).setCellValue((String) child.get("node_name"));
                    row.createCell(4).setCellValue((String) child.get("delay_reason"));
                }
            }
        }
        ByteArrayOutputStream baos = null;
        ServletOutputStream outputStream = null;
        try {
            /*InputStream inputStream = new FileInputStream(workbook);
            byte[] buffer = new byte[1024];*/
            baos = new ByteArrayOutputStream();
            workbook.write(baos);
            //int len;
            /*while ((len = inputStream.read(buffer)) != -1) {
                baos.write(buffer, 0, len);
            }*/
            response.setContentType("application/octet-stream");
            outputStream = response.getOutputStream();
            outputStream.write(baos.toByteArray());
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            baos.flush();
            baos.close();
            outputStream.flush();
            outputStream.close();
        }
    }

    @Override
    public void updateDelayReason(List<ProjectNodeDelayReasonDTO> dtos) {
        for (ProjectNodeDelayReasonDTO dto : dtos) {
            for (ProjectNodeDelayReasonDTO.Child child : dto.getChildren()) {
                // 查询
                ProjectSchedule projectSchedule = scheduleService.selectByProjectIdAndNodeId(dto.getProjectId(), child.getNodeId());
//                System.out.println(projectSchedule);
                String delayReason = child.getDelayReason();
                if (projectSchedule.getDelayReason()==null|| !projectSchedule.getDelayReason().equals(delayReason)){
                    // 更新
                    projectSchedule.setDelayReason(delayReason);
                    scheduleService.updateByProjectIdAndNodeId(projectSchedule);
                }
            }
        }
    }
}




